#include "stdafx.h"
#include "UserSceneQuery.h"
#include <LitSceneManager.h>

UserSceneQuery::Result::HitPoint::HitPoint() : movable(NULL){}
UserSceneQuery::Result::HitPoint::HitPoint(Lit::Vec3 point_,Ogre::MovableObject* obj) : movable(obj), point(point_){}
UserSceneQuery::Result::HitPoint::HitPoint(const HitPoint& rk){ movable = rk.movable; point = rk.point; }
UserSceneQuery::Result::HitPoint::~HitPoint(){}

UserSceneQuery::Result::HitPoint& UserSceneQuery::Result::HitPoint::operator=(const HitPoint& rk){ movable = rk.movable; point = rk.point; return *this; }
			
UserSceneQuery::Result::Result(const Result& rk){ contacts.clear(); flags = rk.flags; volume=rk.volume; hit = rk.hit; contacts = rk.contacts; }
UserSceneQuery::Result::Result():hit(false),volume(false), flags(UQF_NONE){}
UserSceneQuery::Result::~Result(){}
UserSceneQuery::Result& UserSceneQuery::Result::operator=(const Result& rk){ flags = rk.flags; contacts.clear(); volume=rk.volume; hit = rk.hit; contacts = rk.contacts; return *this; }
		
UserSceneQuery::Result::HitPoint& UserSceneQuery::Result::firstContact(){ return contacts.at(0); }
const UserSceneQuery::Result::HitPoint& UserSceneQuery::Result::firstContact() const{ return contacts.at(0); }

Ogre::Ray& UserSceneQuery::userRay(){ return mRay; }
const Ogre::Ray& UserSceneQuery::userRay() const{ return mRay; }
Ogre::RaySceneQuery* UserSceneQuery::userRayQuery(){ return mRayQuery; }
const Ogre::RaySceneQuery* UserSceneQuery::userRayQuery() const{ return mRayQuery; }

Ogre::PlaneBoundedVolume& UserSceneQuery::userVolume(){ return mVolume; }
const Ogre::PlaneBoundedVolume& UserSceneQuery::userVolume() const{ return mVolume; }
Ogre::PlaneBoundedVolumeListSceneQuery* UserSceneQuery::userVolumeQuery(){ return mVolumeQuery; }
const Ogre::PlaneBoundedVolumeListSceneQuery* UserSceneQuery::userVolumeQuery() const{ return mVolumeQuery; }
UserSceneQuery::UserSceneQuery( QWidget * render_parent, Lit::RefPtr<Lit::SceneManager> mgr ) 
	: QWidget(render_parent)
	, mParent( render_parent )
{
	mSceneMgr = mgr;
	mRayQuery = mSceneMgr->createRayQuery( mRay );
	mVolumeQuery = mSceneMgr->createVolumeQuery(mVolume);
	mRayQuery->setQueryMask( UQF_SELECTABLE );
	mVolumeQuery->setQueryMask( UQF_SELECTABLE );
	mRayQuery->setSortByDistance( true );
}
UserSceneQuery::~UserSceneQuery()
{ 
	if( mParent )
	{
	}
	if( mSceneMgr )
	{
		mSceneMgr->destroyQuery( mRayQuery );
		mSceneMgr->destroyQuery( mVolumeQuery );
	}
}

void UserSceneQuery::clearResults()
{
	mRayQuery->clearResults();
	mVolumeQuery->clearResults();
	mLastResult.volume = false;
	mLastResult.hit = false;
	mLastResult.contacts.clear();
}
UserSceneQuery::Result UserSceneQuery::execute( Lit::OgreCameraPtr camera, QPoint local_pos )
{
	Lit::Vec2 Ratio = UserDrag::mouseWidgetRatio( local_pos, mParent->geometry() );
	updateRayQuery( camera, Ratio.x, Ratio.y );
	return mLastResult;
}
UserSceneQuery::Result UserSceneQuery::execute( Lit::OgreCameraPtr camera, QPoint local_pos, QPoint local_pos2 )
{
	Lit::Vec2 RatioStart = UserDrag::mouseWidgetRatio( local_pos, mParent->geometry() );
	Lit::Vec2 RatioEnd = UserDrag::mouseWidgetRatio( local_pos2, mParent->geometry() );
	QPoint sz(local_pos2-local_pos);
	if( sz.x() < MIN_VOLUME_SIZE && 
		sz.y() < MIN_VOLUME_SIZE )
		updateRayQuery( camera, RatioEnd.x, RatioEnd.y );
	else
		updateVolumeQuery( 
			camera,
			RatioStart.x, RatioStart.y,
			RatioEnd.x, RatioEnd.y 
		);
	return mLastResult;
}
void UserSceneQuery::updateRayQuery( Lit::OgreCameraPtr camera, float dx, float dy )
{
	clearResults();
	mRay = camera->getCameraToViewportRay( dx, dy );
	mRayQuery->setRay(mRay);
	mLastResult.flags = UQF_SELECTABLE;
	mLastResult.hit = false;
	mLastResult.volume = false;
	Ogre::RaySceneQueryResult res = mRayQuery->execute();
	for( auto i=res.begin(); i!=res.end(); i++ )
	{
		if( i->movable )
		{
			mLastResult.hit = true;
			mLastResult.contacts.push_back(Result::HitPoint( mRay.getPoint(i->distance), i->movable ));
		}
	}
}
void UserSceneQuery::updateVolumeQuery( Lit::OgreCameraPtr camera, float dx, float dy, float dx2, float dy2 )
{
	clearResults();
	mVolume = camera->getCameraToViewportBoxVolume( dx, dy, dx2, dy2 );
	Ogre::PlaneBoundedVolumeList vols;
	vols.push_back( mVolume );
	mVolumeQuery->setVolumes( vols );
	Ogre::SceneQueryResult res = mVolumeQuery->execute();
	mLastResult.hit = false;
	mLastResult.volume = true;
	mLastResult.flags = UQF_SELECTABLE;

	for( auto i=res.movables.begin(); i!=res.movables.end(); i++ )
	{
		if( (*i) )
		{
			mLastResult.hit = true;
			mLastResult.contacts.push_back(Result::HitPoint( Lit::Vec3::ZERO, (*i) ));
		}
	}
}